💡 AI 인사이트

🤖 AI가 여기에 결과를 출력합니다...

댓글 커뮤니티

쿠팡이벤트

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

검색

    로딩 중이에요... 🐣

    [코담] 웹개발·실전 프로젝트·AI까지, 파이썬·장고의 모든것을 담아낸 강의와 개발 노트

    02 데이터가 저장되고 가공되는 흐름 | ✅ 저자: 이유정(박사)

    데이터 파이프라인 단계별 설명:

    🔹 1단계: DL (Data Lake) – 데이터 레이크

    데이터 레이크는 엑셀, 로그, 크롤링 결과, 이미지, 센서 정보 등 다양한 원시(raw) 데이터를 있는 그대로 저장하는 공간입니다.
    정제되지 않은 데이터라도 모두 저장할 수 있어, 이후 분석이나 가공을 위한 출발점 역할을 합니다.

    ✅ 원시 데이터 저장소

    • CSV, JSON, 크롤링 결과, 공공데이터 API 등에서 수집한 원시 데이터
    • 저장 위치: raw_data/restaurant_raw_data.csv, json_files/naver_blog_reviews.json

    내용 예시:

    {
      "가게명": "브런치카페 강남점",
      "주소": "서울 강남구 테헤란로...",
      "리뷰": "진짜 맛있어요!",
      "별점": "⭐⭐⭐⭐",
      "카테고리": "카페, 양식",
      "전화번호": "+82-02-1234-5678",
      "운영시간": "09:00~21:00",
      "위도": "37.123456789012",
      "경도": "127.123456789012"
    }
    

    ✔ 이 데이터는 아직 불완전합니다.
    ✔ 필드명 불일치, 단위 불명확, 주소 파싱 필요 등 → 정제 필요


    🔹 2단계: DW (Data Warehouse) – 데이터 웨어하우스

    데이터 웨어하우스는 데이터 레이크에 저장된 원시 데이터를 깨끗하게 정리하고 표 형태로 구조화하여 저장하는 공간입니다.
    주로 BI 도구, 리포트 작성, 분석 작업에 활용됩니다.
    즉, 분석하기 쉬운 형태로 가공된 데이터를 저장하는 곳이에요.

    ✅ 원시 데이터를 정제·표준화한 구조화 테이블

    • 주소 파싱 → Region 테이블 기준으로 나누기
    • 별점 변환: ⭐⭐⭐⭐ → 숫자 4
    • 운영시간 분리 → start_time, end_time, last_order_time
    • 카테고리 정리 → RestaurantCategory, CuisineType 분리
    • 중복 가게 제거, 결측치 채움, 전화번호 포맷 정규화 등

    중간 결과: cleaned_restaurant_data.csv
    → 이 파일을 기반으로 다음 단계로 이동

    {
      "name": "브런치카페 강남점",
      "branch_name": "강남점",
      "address": "서울 강남구 테헤란로...",
      "feature": "저렴한 가격, 빠른 제공",
      "rating": 4.2,
      "category": "분식",
      "start_time": "09:00",
      "end_time": "21:00",
      "region": "서울 강남구 역삼동",
      ...
    }
    

    🔹 3단계: DM (Data Mart) – 데이터 마트

    데이터 마트는 웨어하우스에 있는 데이터를 부서별(예: 마케팅팀, 영업팀) 또는 목적별로 잘라서 보관하는 작은 데이터 저장소입니다.
    필요한 데이터만 골라 빠르게 분석하거나 사용할 수 있도록 설계되어 있어요.

    ✅ 특정 목적(뷰/부서별)을 위한 소규모 테이블 이 단계에서는 DW의 정제된 데이터를 아래 목적별로 분리 저장

    상점명 목적 설명
    dm_top_rated_restaurants 추천용 평점 4.5 이상 + 리뷰 10개 이상 맛집 리스트
    dm_new_restaurants 홍보용 최근 한 달 이내 등록된 레스토랑
    dm_popular_tags 검색 분석 가장 자주 사용된 태그별 집계
    dm_region_based_stats 리포트 지역별 레스토랑 수, 평균 평점, 리뷰 수 등 통계
    Django에는 직접 모델로 만들지 않고, View나 임시 테이블로 활용하거나 통계 API에서 사용

    🔹 4단계: Service DB – 서비스 데이터베이스

    서비스 DB는 실제 웹사이트나 모바일 앱에서 사용되는 데이터베이스입니다.
    예를 들어, 사용자가 로그인하거나 상품을 추천받을 때, 바로 이 DB의 정보를 활용하게 됩니다.
    즉, 실시간으로 고객에게 서비스를 제공하는 데 직접 쓰이는 DB입니다.

    ✅ Django 모델 기반 실서비스용 데이터베이스 이 부분은 지금 이미 구축한 models.py가 해당됩니다!
    각 모델은 다음처럼 구성되어 있고, Admin / API / 사용자 인터페이스에서 직접 사용됩니다:

    모델 역할
    Restaurant 핵심 맛집 정보 저장 (이름, 주소, 위도/경도, 시간 등)
    Region 주소 파싱 결과로 지역 분류 저장 (시도, 구, 동)
    RestaurantCategory / CuisineType 음식 분류 저장 (한식, 일식, 카페 등)
    Tag #혼밥, #데이트 같은 사용자/시스템 태그
    RestaurantMenu 메뉴 정보 저장
    RestaurantImage 대표 이미지 및 기타 이미지 저장
    Review 사용자 후기 저장
    ReviewImage 후기 이미지 저장
    SocialChannel 블로그, 인스타그램 등 채널 구분용
    Article 관리자 작성 칼럼 (추천 콘텐츠 등)

    정제된 CSV는 다음과 같은 구조라고 가정하면:

    name,branch_name,address,feature,latitude,longitude,phone,rating,
    rating_count,start_time,end_time,last_order_time,category_name,
    cuisine_type,region_sido,region_sigungu,region_eupmyeondong,
    tags
    
    김밥천국,강남점,서울 강남구 테헤란로,저렴한 가격,37.1234,127.1234,+82-2-1234-5678,4.2,15,09:00,21:00,20:30,분식,한식,서울,강남구,역삼동,
    #혼밥,#가성비
    

    Step 1. CSV 읽기

    import pandas as pd
    df = pd.read_csv("csv_files/cleaned_restaurant_data.csv")
    

    Step 2. 각 모델에 맞게 데이터 분리 & 저장

    from restaurant.models import (
        Restaurant, Region, RestaurantCategory, CuisineType, Tag
    )
    from django.utils.dateparse import parse_time
    
    for i, row in df.iterrows():
        # 1. 지역 처리 (Region)
        region, _ = Region.objects.get_or_create(
            sido=row["region_sido"],
            sigungu=row["region_sigungu"],
            eupmyeondong=row["region_eupmyeondong"],
        )
    
        # 2. 음식 종류 처리 (CuisineType)
        cuisine_type, _ = CuisineType.objects.get_or_create(name=row["cuisine_type"])
    
        # 3. 카테고리 처리 (RestaurantCategory)
        category, _ = RestaurantCategory.objects.get_or_create(
            name=row["category_name"],
            defaults={"cuisine_type": cuisine_type},
        )
    
        # 4. 레스토랑 저장 (Restaurant)
        restaurant = Restaurant.objects.create(
            name=row["name"],
            branch_name=row["branch_name"],
            address=row["address"],
            feature=row["feature"],
            latitude=row["latitude"],
            longitude=row["longitude"],
            phone=row["phone"],
            rating=row["rating"],
            rating_count=row["rating_count"],
            start_time=parse_time(str(row["start_time"])),
            end_time=parse_time(str(row["end_time"])),
            last_order_time=parse_time(str(row["last_order_time"])),
            category=category,
            region=region,
        )
    
        # 5. 태그 저장 및 연결 (ManyToManyField)
        tags = str(row["tags"]).split(",")
        for tag_name in tags:
            tag_name = tag_name.strip().lstrip("#")
            if tag_name:
                tag, _ = Tag.objects.get_or_create(name=tag_name)
                restaurant.tags.add(tag)
    

    데이터는 수집(DL) → 정제(DW) → 분류(DM) → 서비스(Service DB) 단계로 점점 깨끗하고 목적에 맞게 정돈되어 실제 서비스에 활용됩니다.


    자주 사용되는 Pandas 메서드

    1. read_csv() CSV 파일을 읽어서 DataFrame으로 불러오기
    import pandas as pd  
    df = pd.read_csv("data.csv")
    

    1. to_csv() DataFrame을 CSV 파일로 저장
    df.to_csv("output.csv", index=False)
    

    1. head() 처음 5줄(기본값) 보기
    df.head()  # df.head(10) → 처음 10줄 보기
    

    1. tail() 마지막 5줄 보기
    df.tail()  # df.tail(3) → 마지막 3줄 보기
    

    1. describe() 숫자형 열의 요약 통계 (평균, 표준편차, 최대/최소 등)
    df.describe()
    

    1. info() 열 이름, 결측치 여부, 데이터 타입 등 기본 정보
    df.info()
    

    1. mean() 열 평균 계산
    df["age"].mean()
    

    1. median() 열의 중앙값
    df["salary"].median()
    

    1. max() 최대값 찾기
    df["score"].max()
    

    1. min() 최소값 찾기
    df["score"].min()
    

    1. drop() 열 또는 행 삭제
    # 열 삭제 
    df.drop("email", axis=1, inplace=True)  
    
    # 행 삭제 (index 기준) 
    df.drop(0, axis=0)
    

    1. fillna() 결측치 채우기
    df["age"].fillna(30, inplace=True)  # 결측치를 30으로
    

    1. isnull() 결측치 여부 확인
    df.isnull()  # True/False로 표시 
    df["age"].isnull().sum()  # age 열의 결측치 개수
    

    1. groupby() 열 기준으로 그룹화 후 계산
    df.groupby("gender")["salary"].mean()
    

    1. merge() 두 DataFrame 병합 (SQL의 JOIN과 유사)
    df1.merge(df2, on="user_id", how="inner")
    

    1. concat() 위 또는 옆으로 데이터 연결
    pd.concat([df1, df2], axis=0)  # 위아래 연결 
    pd.concat([df1, df2], axis=1)  # 좌우 연결
    

    1. value_counts() 고유값 개수 세기
    df["gender"].value_counts()
    

    1. sort_values() 열 기준 정렬
    df.sort_values(by="score", ascending=False)
    

    1. pivot_table() 피벗 테이블 (엑셀처럼 요약 테이블)
    df.pivot_table(index="department", values="salary", aggfunc="mean")
    

    1. apply() 함수 적용
    # 각 이름 앞에 "Mr./Ms." 붙이기 
    df["name"].apply(lambda x: "Mr. " + x)
    

    TOP
    preload preload